"""
缺陷管理服务层
将缺陷相关的业务逻辑从API层迁移到服务层
"""
from datetime import datetime, timedelta
import logging
from typing import List, Optional, Dict, Any, Union
from bson import ObjectId, errors  # pyright: ignore[reportMissingImports]
from motor.motor_asyncio import AsyncIOMotorDatabase  # pyright: ignore[reportMissingImports]
from fastapi import HTTPException  # pyright: ignore[reportMissingImports]
from pymongo import ASCENDING, DESCENDING  # pyright: ignore[reportMissingImports]
try:
    from fastapi import status as http_status_module  # 避免与参数名 status 冲突
except ImportError:
    from starlette import status as http_status_module  # 后备导入

from app.schemas.defect import (
    DefectCreate,
    DefectUpdate,
    DefectStatusUpdate,
    DefectAssigneeUpdate,
    DefectResponse,
    DefectSummary,
    DefectStats,
)
from app.models.defect import (
    DefectPriority,
    DefectSeverity,
    DefectType,
    DefectSource,
)
from app.core.permissions import Permissions
from app.services.permission_service import PermissionService
from app.services.notification_service import NotificationService
from app.models.notification import NotificationCreate, NotificationType, RelatedObjectType
from app.utils.task_utils import format_defect_response
from app.utils.state_utils import validate_state_code
import asyncio

logger = logging.getLogger(__name__)


class DefectService:
    """缺陷服务类，封装缺陷相关的业务逻辑"""
    
    def __init__(self, db: AsyncIOMotorDatabase):
        self.db = db
        self._state_validator = None  # 缓存状态验证器实例
    
    @staticmethod
    def _get_status_code(status_name: str, default: int = 500) -> int:
        """安全地获取HTTP状态码"""
        try:
            if http_status_module is None:
                return default
            return getattr(http_status_module, status_name, default)
        except (AttributeError, TypeError):
            return default
    
    def _to_object_id(self, value: Any, field_name: str = "ID") -> Optional[ObjectId]:
        """将值转换为ObjectId，如果无效则返回None"""
        if value is None:
            return None
        if isinstance(value, ObjectId):
            return value
        if isinstance(value, str) and ObjectId.is_valid(value):
            return ObjectId(value)
        return None
    
    def _validate_object_id(self, value: Any, field_name: str = "ID") -> ObjectId:
        """验证并转换ObjectId，如果无效则抛出异常"""
        obj_id = self._to_object_id(value, field_name)
        if obj_id is None:
            raise HTTPException(
                status_code=self._get_status_code('HTTP_400_BAD_REQUEST', 400),
                detail=f"无效的{field_name}格式"
            )
        return obj_id
    
    def _parse_datetime_string(self, date_str: Optional[str]) -> Optional[datetime]:
        """解析日期时间字符串"""
        if not date_str:
            return None
        try:
            dt = datetime.fromisoformat(date_str)
            # 如果只有日期部分，时间部分为00:00:00，则设置为当天的23:59:59
            if dt.time() == datetime.min.time():
                dt = dt + timedelta(days=1) - timedelta(microseconds=1)
            return dt
        except ValueError:
            try:
                dt = datetime.strptime(date_str, "%Y-%m-%d")
                dt = dt + timedelta(days=1) - timedelta(microseconds=1)
                return dt
            except ValueError:
                return None
    
    def _parse_tags_string(self, tags_str: Optional[str]) -> Optional[List[str]]:
        """解析标签字符串为列表"""
        if not tags_str:
            return None
        try:
            return [tag.strip() for tag in tags_str.split(",") if tag.strip()]
        except (AttributeError, TypeError):
            return None
    
    async def _get_version_defect_ids(self, version_id: Optional[str]) -> Optional[List[ObjectId]]:
        """获取版本关联的缺陷ID列表"""
        if not version_id:
            return None
        try:
            version_obj_id = self._validate_object_id(version_id, "版本ID")
            defect_relations = await self.db.version_defect_relations.find(
                {"version_id": version_obj_id}
            ).limit(10000).to_list(length=10000)
            defect_ids = [relation["defect_id"] for relation in defect_relations]
            return defect_ids if defect_ids else None
        except Exception:
            raise HTTPException(
                status_code=self._get_status_code('HTTP_400_BAD_REQUEST', 400),
                detail="Invalid version_id format"
            )
    
    async def get_defects(
        self,
        user: dict,
        skip: int = 0,
        limit: int = 20,
        search: Optional[str] = None,
        project_id: Optional[str] = None,
        requirement_id: Optional[str] = None,
        assignee_id: Optional[str] = None,
        reporter_id: Optional[str] = None,
        status: Optional[Union[str, List[str]]] = None,
        priority: Optional[Union[DefectPriority, str]] = None,
        severity: Optional[Union[DefectSeverity, str]] = None,
        defect_type: Optional[Union[DefectType, str]] = None,
        source: Optional[Union[DefectSource, str]] = None,
        found_date_start: Optional[Union[str, datetime]] = None,
        found_date_end: Optional[Union[str, datetime]] = None,
        tags: Optional[Union[str, List[str]]] = None,
        version_id: Optional[str] = None,
        sort_by: str = "created_at",
        sort_order: str = "desc",
    ) -> List[Dict[str, Any]]:
        """获取缺陷列表"""
        try:
            # 参数转换：处理版本ID筛选
            version_defect_ids = None
            if version_id:
                version_defect_ids = await self._get_version_defect_ids(version_id)
                if not version_defect_ids:
                    return []
            
            # 参数转换：处理时间字符串
            found_start_dt = found_date_start
            if isinstance(found_date_start, str):
                found_start_dt = self._parse_datetime_string(found_date_start)
            
            found_end_dt = found_date_end
            if isinstance(found_date_end, str):
                found_end_dt = self._parse_datetime_string(found_date_end)
            
            # 参数转换：处理标签字符串
            tags_list = tags
            if isinstance(tags, str):
                tags_list = self._parse_tags_string(tags)
            
            # 构建基础查询条件
            base_query = {}
            
            if search:
                base_query["$and"] = base_query.get("$and", [])
                base_query["$and"].append({
                    "$or": [
                        {"title": {"$regex": search, "$options": "i"}},
                        {"description": {"$regex": search, "$options": "i"}},
                        {"steps_to_reproduce": {"$regex": search, "$options": "i"}},
                        {"tags": {"$regex": search, "$options": "i"}}
                    ]
                })
            
            if project_id:
                base_query["project_id"] = self._validate_object_id(project_id, "项目ID")
            
            if requirement_id:
                base_query["requirement_id"] = self._validate_object_id(requirement_id, "需求ID")
            
            if assignee_id:
                base_query["assignee_id"] = self._validate_object_id(assignee_id, "负责人ID")
            
            if reporter_id:
                base_query["reporter_id"] = self._validate_object_id(reporter_id, "报告人ID")
            
            if status:
                status_list = status if isinstance(status, list) else [status]
                if len(status_list) == 1:
                    base_query["status"] = status_list[0]
                else:
                    base_query["status"] = {"$in": status_list}
            
            if priority:
                priority_value = priority.value if hasattr(priority, 'value') else priority
                base_query["priority"] = priority_value
            
            if severity:
                severity_value = severity.value if hasattr(severity, 'value') else severity
                base_query["severity"] = severity_value
            
            if defect_type:
                type_value = defect_type.value if hasattr(defect_type, 'value') else defect_type
                base_query["type"] = type_value
            
            if source:
                source_value = source.value if hasattr(source, 'value') else source
                base_query["source"] = source_value
            
            # 日期范围筛选
            if found_start_dt or found_end_dt:
                date_query = {}
                if found_start_dt:
                    date_query["$gte"] = found_start_dt
                if found_end_dt:
                    date_query["$lte"] = found_end_dt
                base_query["found_date"] = date_query
            
            if tags_list:
                base_query["tags"] = {"$in": tags_list}
            
            # 如果通过version_id筛选，添加缺陷ID限制
            if version_defect_ids:
                base_query["_id"] = {"$in": version_defect_ids}
            
            # 使用统一的数据权限过滤方法
            query = await PermissionService.build_data_permission_query(
                user=user,
                db=self.db,
                module_type="defect",
                base_query=base_query,
                project_id_field="project_id",
                assignee_id_field="assignee_id",
                reporter_id_field="reporter_id",
                creator_id_field="created_by",
                read_all_permission=Permissions.DEFECT_READ_ALL
            )
            
            # 排序
            sort_direction = ASCENDING if sort_order == "asc" else DESCENDING
            sort_criteria = [(sort_by, sort_direction)]
            
            # 查询缺陷
            cursor = self.db.defects.find(query).sort(sort_criteria).skip(skip).limit(limit)
            defects = await cursor.to_list(length=limit)
            
            # 格式化响应数据
            formatted_defects = []
            for defect in defects:
                formatted_defect = format_defect_response(defect)
                formatted_defects.append(formatted_defect)
            
            return formatted_defects
            
        except HTTPException:
            raise
        except Exception as e:
            logger.error(f"获取缺陷列表失败: {str(e)}", exc_info=True)
            raise HTTPException(
                status_code=self._get_status_code('HTTP_500_INTERNAL_SERVER_ERROR', 500),
                detail=f"获取缺陷列表失败: {str(e)}"
            )
    
    async def get_defects_count(
        self,
        user: dict,
        search: Optional[str] = None,
        project_id: Optional[str] = None,
        requirement_id: Optional[str] = None,
        assignee_id: Optional[str] = None,
        reporter_id: Optional[str] = None,
        status: Optional[Union[str, List[str]]] = None,
        priority: Optional[Union[DefectPriority, str]] = None,
        severity: Optional[Union[DefectSeverity, str]] = None,
        defect_type: Optional[Union[DefectType, str]] = None,
        source: Optional[Union[DefectSource, str]] = None,
        found_date_start: Optional[Union[str, datetime]] = None,
        found_date_end: Optional[Union[str, datetime]] = None,
        tags: Optional[Union[str, List[str]]] = None,
        version_id: Optional[str] = None,
    ) -> int:
        """获取缺陷总数"""
        try:
            # 使用相同的查询逻辑构建查询条件
            # 这里可以复用get_defects的查询构建逻辑
            # 为了简化，直接调用get_defects的查询构建部分
            # 实际实现中应该提取公共方法
            
            # 参数转换：处理版本ID筛选
            version_defect_ids = None
            if version_id:
                version_defect_ids = await self._get_version_defect_ids(version_id)
                if not version_defect_ids:
                    return 0
            
            # 构建基础查询条件（与get_defects相同）
            base_query = {}
            
            if search:
                base_query["$and"] = base_query.get("$and", [])
                base_query["$and"].append({
                    "$or": [
                        {"title": {"$regex": search, "$options": "i"}},
                        {"description": {"$regex": search, "$options": "i"}},
                        {"steps_to_reproduce": {"$regex": search, "$options": "i"}},
                        {"tags": {"$regex": search, "$options": "i"}}
                    ]
                })
            
            if project_id:
                base_query["project_id"] = self._validate_object_id(project_id, "项目ID")
            
            if requirement_id:
                base_query["requirement_id"] = self._validate_object_id(requirement_id, "需求ID")
            
            if assignee_id:
                base_query["assignee_id"] = self._validate_object_id(assignee_id, "负责人ID")
            
            if reporter_id:
                base_query["reporter_id"] = self._validate_object_id(reporter_id, "报告人ID")
            
            if status:
                status_list = status if isinstance(status, list) else [status]
                if len(status_list) == 1:
                    base_query["status"] = status_list[0]
                else:
                    base_query["status"] = {"$in": status_list}
            
            if priority:
                priority_value = priority.value if hasattr(priority, 'value') else priority
                base_query["priority"] = priority_value
            
            if severity:
                severity_value = severity.value if hasattr(severity, 'value') else severity
                base_query["severity"] = severity_value
            
            if defect_type:
                type_value = defect_type.value if hasattr(defect_type, 'value') else defect_type
                base_query["type"] = type_value
            
            if source:
                source_value = source.value if hasattr(source, 'value') else source
                base_query["source"] = source_value
            
            # 日期范围筛选
            found_start_dt = found_date_start
            if isinstance(found_date_start, str):
                found_start_dt = self._parse_datetime_string(found_date_start)
            
            found_end_dt = found_date_end
            if isinstance(found_date_end, str):
                found_end_dt = self._parse_datetime_string(found_date_end)
            
            if found_start_dt or found_end_dt:
                date_query = {}
                if found_start_dt:
                    date_query["$gte"] = found_start_dt
                if found_end_dt:
                    date_query["$lte"] = found_end_dt
                base_query["found_date"] = date_query
            
            tags_list = tags
            if isinstance(tags, str):
                tags_list = self._parse_tags_string(tags)
            
            if tags_list:
                base_query["tags"] = {"$in": tags_list}
            
            # 如果通过version_id筛选，添加缺陷ID限制
            if version_defect_ids:
                base_query["_id"] = {"$in": version_defect_ids}
            
            # 使用统一的数据权限过滤方法
            query = await PermissionService.build_data_permission_query(
                user=user,
                db=self.db,
                module_type="defect",
                base_query=base_query,
                project_id_field="project_id",
                assignee_id_field="assignee_id",
                reporter_id_field="reporter_id",
                creator_id_field="created_by",
                read_all_permission=Permissions.DEFECT_READ_ALL
            )
            
            # 获取总数
            total = await self.db.defects.count_documents(query)
            return total
            
        except HTTPException:
            raise
        except Exception as e:
            logger.error(f"获取缺陷总数失败: {str(e)}", exc_info=True)
            raise HTTPException(
                status_code=self._get_status_code('HTTP_500_INTERNAL_SERVER_ERROR', 500),
                detail=f"获取缺陷总数失败: {str(e)}"
            )

